iT邦幫忙

2022 iThome 鐵人賽

DAY 8
1
Software Development

30天學會Golang系列 第 8

Day08 - Go的錯誤處理(error handling)

  • 分享至 

  • xImage
  •  

錯誤處理

一個好的工程師,就是有好的除錯能力,有效率的除錯方式,就是在執行程式時,出錯時能回報有效的錯誤訊息,因此錯誤處理是一件非常重要的事。這裡我事先聲明,大部分都是參照 參考來源1 的寫法,因為覺得講得很不錯,就用這篇內容作為例子講解,如果有版權問題的話,請提醒我!

產生錯誤訊息的方式就是 errors.New(),如下所示:

err := errors.New("建立錯誤訊息")

由於 error 在 go 中的定義是一個 interface,透過 day06 的概念,表示我們也可以製作自己的錯誤訊息

type error interface {
  Error() string
}

製作自定義的錯誤訊息,常見寫法如下:

// STEP 1:定義客製化的 error struct
type MyError struct {
	Time    time.Time
	Message string
}

// STEP 2:定義能夠屬於 Error Interface 的方法
func (e *MyError) Error() string {
	return fmt.Sprintf("喔耶,已經%v了,%s", e.Time.Format("15:04:05"), e.Message)
}

// STEP 3:拋出錯誤的函式
func errHandler(status bool) (error, bool) {
	if status {
		return nil, true
	}
	return &MyError{
		Time:    time.Now(),
		Message: "我要來耍廢了",
	}, false
}

// STEP 4:使用 fmt.Println 即可取得錯誤拋出的訊息
func main() {
	result := run(errHandler)
	result(true)
	result(false)
}

// PS 只是讓程式碼比較好看的改寫,不一定需要
func run(op func(status bool) (error, bool)) func(bool) {
	return func(status bool) {
		if err, ok := op(status); ok {
			fmt.Println("ok")
		} else {
			fmt.Println(err)
		}
	}
}

輸出結果為:

ok
喔耶,已經22:22:22了,我要來耍廢了

但是有時候我們可能會遇到更多情況,比方說我們想給使用者看到的訊息與伺服器 log 的錯誤訊息不同,那麼我們該怎麼做?以上面的例子為例,這時候我們就可以使用 err.(MyError) 來看看是不是我們定義的錯誤類別,所以表示我們可以創建多種不同的錯誤 struct,然後用同樣的邏輯來判斷屬於什麼類型 struct 的錯誤訊息,以下為例:

判斷 error 型態的寫法:

errorStruct, isErrorStruct := err.(ErrorStruct)

實際操作:

// // 情境1: 簡易的 error handling
// // STEP 1:定義客製化的 error struct
// type MyError struct {
// 	Time    time.Time
// 	Message string
// }

type YourError struct {
	Time    time.Time
	Message string
}

// // STEP 2:定義能夠屬於 Error Interface 的方法
// func (e *MyError) Error() string {
// 	return fmt.Sprintf("喔耶,已經%v了,%s", e.Time.Format("15:04:05"), e.Message)
// }

func (e *YourError) Error() string {
	return fmt.Sprintf("已經%v了,%s", e.Time.Format("15:04:05"), e.Message)
}

// // STEP 3:拋出錯誤的函式
// func errHandler(status bool) (error, bool) {
// 	if status {
// 		return nil, true
// 	}
// 	return &MyError{
// 		Time:    time.Now(),
// 		Message: "我要來耍廢了",
// 	}, false
// }

func yourErrHandler(status bool) (error, bool) {
	if status {
		return nil, true
	}
	return &YourError{
		Time:    time.Now(),
		Message: "換你耍廢了",
	}, false
}

// STEP 4:使用 fmt.Println 即可取得錯誤拋出的訊息
func main() {
	// result := run(errHandler)
	// result(true)
	// result(false)
	isMyError(errHandler)
	isMyError(yourErrHandler)
}

// PS 只是讓程式碼比較好看的改寫,不一定需要
type errType func(bool) (error, bool)

// // PS 只是讓程式碼比較好看的改寫,不一定需要
// func run(op errType) func(bool) {
// 	return func(status bool) {
// 		if err, ok := op(status); ok {
// 			fmt.Println("ok")
// 		} else {
// 			fmt.Println(err)
// 		}
// 	}
// }

func isMyError(op errType) {
	err, _ := op(false)
	if err != nil {
		switch err.(type) {
		case *MyError:
			fmt.Println("MyError: ", err)
		case *YourError:
			fmt.Println("YourError: ", err)
		default:
			fmt.Println("沒有定義是誰的錯")
		}
	}
}
第8天報到,原來還有這種錯誤處理,挺有趣的,以後應該要來善用一下: )

參考來源

  1. https://pjchender.dev/golang/error-handling/

代碼連結

https://github.com/luckyuho/ithome30-golang/tree/main/day08


上一篇
Day07 - Go的閉包
下一篇
Day09 - Go的單元測試 (上)
系列文
30天學會Golang31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言